﻿namespace FiftyOne.Foundation.Mobile.Detection.Wurfl
{
    using FiftyOne;
    using FiftyOne.Foundation.Mobile.Detection.Wurfl.Configuration;
    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.IO.Compression;
    using System.Xml;
    using System.Xml.Schema;

    internal static class WurflProcessor
    {
        private static StringCollection _capabilitiesWhiteListed = new StringCollection();
        private static bool _loadOnlyCapabilitiesWhiteListed;
        private static readonly string[] COMPRESSED = new string[] { ".gz" };

        static WurflProcessor()
        {
            foreach (string str in Constants.DefaultUsedCapabilities)
            {
                _capabilitiesWhiteListed.Add(str);
            }
        }

        private static XmlReaderSettings GetXmlReaderSettings()
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.IgnoreWhitespace = true;
            settings.ConformanceLevel = ConformanceLevel.Auto;
            settings.ValidationType = ValidationType.Schema;
            settings.ValidationFlags = XmlSchemaValidationFlags.ProcessSchemaLocation;
            return settings;
        }

        private static bool IsCompressed(FileInfo file)
        {
            foreach (string str in COMPRESSED)
            {
                if (file.Extension == str)
                {
                    return true;
                }
            }
            return false;
        }

        private static void LoadCapabilityData(XmlReader reader, DeviceInfo device, StringCollection availableCapabilities)
        {
            string attribute = reader.GetAttribute("name", string.Empty);
            if (!_loadOnlyCapabilitiesWhiteListed || _capabilitiesWhiteListed.Contains(attribute))
            {
                string str2 = reader.GetAttribute("value", string.Empty);
                if (!availableCapabilities.Contains(attribute))
                {
                    availableCapabilities.Add(attribute);
                }
                device.Capabilities.Set(attribute, str2);
            }
        }

        private static void LoadXmlData(StringCollection availableCapabilities, Provider devices, string filePath, DateTime masterFileDate)
        {
            XmlReaderSettings xmlReaderSettings = GetXmlReaderSettings();
            DeviceInfo device = null;
            FileInfo file = new FileInfo(filePath);
            Stream stream = null;
            GZipStream input = null;
            XmlReader reader = null;
            bool flag = false;
            bool result = false;
            if (file.Exists)
            {
                try
                {
                    if (IsCompressed(file))
                    {
                        stream = File.OpenRead(filePath);
                        input = new GZipStream(stream, CompressionMode.Decompress);
                        reader = XmlReader.Create(input);
                    }
                    else
                    {
                        reader = XmlReader.Create(file.FullName, xmlReaderSettings);
                    }
                    while (reader.Read())
                    {
                        string name = reader.Name;
                        if (name != null)
                        {
                            if (!(name == "Created"))
                            {
                                if (name == "device")
                                {
                                    goto Label_010A;
                                }
                                if (name == "capability")
                                {
                                    goto Label_0244;
                                }
                            }
                            else
                            {
                                flag = true;
                                if (((device != null) && reader.IsStartElement()) && (reader.ReadElementContentAsDateTime() < masterFileDate))
                                {
                                    EventLog.Debug(string.Format("Device ID '{0}' has not been loaded as it was created prior to the current master file.", device.DeviceId));
                                    device = null;
                                }
                            }
                        }
                        continue;
                    Label_010A:
                        if (reader.IsStartElement())
                        {
                            if (device != null)
                            {
                                devices.Set(device);
                                device = null;
                            }
                            string attribute = reader.GetAttribute("id", string.Empty);
                            string userAgent = reader.GetAttribute("user_agent", string.Empty);
                            string deviceID = reader.GetAttribute("fall_back", string.Empty);
                            device = devices.GetDeviceInfoFromID(attribute);
                            if (device == null)
                            {
                                device = new DeviceInfo(devices, attribute, userAgent);
                            }
                            else
                            {
                                device.SetUserAgent(userAgent);
                            }
                            if (bool.TryParse(reader.GetAttribute("actual_device_root", string.Empty), out result))
                            {
                                device.IsActualDeviceRoot = result;
                            }
                            if ((device.DeviceId != deviceID) && (deviceID != null))
                            {
                                device.FallbackDevice = devices.GetDeviceInfoFromID(deviceID);
                                if (!((device.FallbackDevice != null) || flag))
                                {
                                    device.FallbackDevice = new DeviceInfo(devices, deviceID);
                                    devices.Set(device.FallbackDevice);
                                }
                            }
                            if (flag && (device.FallbackDevice == null))
                            {
                                device = null;
                            }
                        }
                        continue;
                    Label_0244:
                        if (reader.IsStartElement())
                        {
                            LoadCapabilityData(reader, device, availableCapabilities);
                        }
                    }
                    if (device != null)
                    {
                        devices.Set(device);
                        device = null;
                    }
                }
                catch (XmlException exception)
                {
                    throw new WurflException(string.Format("XML exception processing wurfl file '{0}'.", filePath), exception);
                }
                catch (IOException exception2)
                {
                    throw new WurflException(string.Format("IO exception processing wurfl file '{0}'.", filePath), exception2);
                }
                catch (Exception exception3)
                {
                    throw new WurflException(string.Format("Exception processing wurfl file '{0}'.", filePath), exception3);
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }
                    if (input != null)
                    {
                        input.Close();
                        input.Dispose();
                    }
                    if (stream != null)
                    {
                        stream.Close();
                        stream.Dispose();
                    }
                }
            }
        }

        internal static void ParseWurflFiles(Provider devices)
        {
            ParseWurflFiles(devices, Manager.WurflFilePath, Manager.CapabilitiesWhiteList, Manager.WurflPatchFiles);
        }

        private static void ParseWurflFiles(Provider devices, StringCollection wurflFilePaths, DateTime masterFileDate)
        {
            StringCollection availableCapabilities = new StringCollection();
            foreach (string str in wurflFilePaths)
            {
                LoadXmlData(availableCapabilities, devices, str, masterFileDate);
            }
        }

        private static void ParseWurflFiles(Provider devices, string wurflFilePath, params string[] wurflPatchFiles)
        {
            ParseWurflFiles(devices, wurflFilePath, null, wurflPatchFiles);
        }

        private static void ParseWurflFiles(Provider devices, string wurflFilePath, StringCollection capabilitiesWhiteList, params string[] wurflPatchFiles)
        {
            if (string.IsNullOrEmpty(wurflFilePath))
            {
                throw new ArgumentNullException("wurflFilePath");
            }
            if (!File.Exists(wurflFilePath))
            {
                throw new FileNotFoundException("The WURFL XML file was not found, check the file path and try again.", wurflFilePath);
            }
            if (capabilitiesWhiteList != null)
            {
                _loadOnlyCapabilitiesWhiteListed = capabilitiesWhiteList.Count > 0;
                foreach (string str in capabilitiesWhiteList)
                {
                    if (!_capabilitiesWhiteListed.Contains(str))
                    {
                        _capabilitiesWhiteListed.Add(str);
                    }
                }
            }
            StringCollection wurflFilePaths = new StringCollection();
            wurflFilePaths.Add(wurflFilePath);
            wurflFilePaths.AddRange(wurflPatchFiles);
            ParseWurflFiles(devices, wurflFilePaths, File.GetCreationTimeUtc(wurflFilePath));
        }
    }
}

